<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="shortcut icon" href="#" type="image/x-icon" />
    <title>free-api-use-by-react</title>
    <style>
      html,
      body,
      #app {
        margin: 0;
        padding: 0;
        height: 100%;
        overflow: hidden;
      }

      #app {
        display: flex;
        flex-wrap: wrap;
        justify-content: space-evenly;
        padding-top: 10px;
        overflow-y: auto;
        background-image: url('http://api.botwl.cn/api/bing?type=image');
      }

      .container {
        width: 300px;
        height: 400px;
        margin: 10px;
        padding: 10px;
        border-radius: 20px;
        text-align: center;
        border: 1px solid #dfd4d44d;
        box-shadow: 2px 3px 1px 0px #dfd4d44d;
        background-color: rgba(255, 255, 255, 0.85);
      }

      .title {
        cursor: pointer;
        user-select: none;
      }

      .pray-sticks .content {
        display: flex;
        align-items: start;
        justify-content: space-evenly;
        height: calc(100% - 110px);
        cursor: pointer;
      }

      .pray-sticks p {
        writing-mode: vertical-lr;
        cursor: auto;
      }

      .netease-music .preview {
        width: 40%;
        height: 40%;
        border-radius: 50%;
        cursor: pointer;
      }

      @keyframes rotation {
        from {
          -webkit-transform: rotate(0deg);
        }

        to {
          -webkit-transform: rotate(360deg);
        }
      }

      @-webkit-keyframes rotation {
        from {
          -webkit-transform: rotate(0deg);
        }

        to {
          -webkit-transform: rotate(360deg);
        }
      }

      .netease-music .preview-rotation {
        transform: rotate(360deg);
        -webkit-transform: rotate(360deg);
        animation: rotation 10s linear infinite;
        -moz-animation: rotation 10s linear infinite;
        -webkit-animation: rotation 10s linear infinite;
        -o-animation: rotation 10s linear infinite;
      }

      audio:focus,
      input,
      button,
      video,
      video:focus {
        outline: none;
        border: none;
      }

      button {
        height: 28px;
        cursor: pointer;
      }

      .short-video .content {
        display: flex;
        height: 80%;
      }
      .short-video .content .left {
        display: flex;
        flex-direction: column;
        justify-content: center;
        padding-left: 10px;
        font-size: 30px;
      }
      .short-video .content .left span {
        cursor: pointer;
      }

      .short-video .content .right {
        flex: 1;
      }

      .short-video .video {
        width: 70%;
        height: 100%;
        object-fit: fill;
        border-radius: 1.5%;
        cursor: pointer;
      }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
    <!-- <script src="https://unpkg.com/react@18/umd/react.production.min.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" crossorigin></script> -->
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  </head>
  <body>
    <div id="app"></div>
    <script type="text/babel">
      // https://bird.ioliu.cn/v2/ 可以作为 HTTP 代理接口
      const proxyInterface = 'https://bird.ioliu.cn/v2/'
      const ele = React.createElement
      const useState = React.useState
      const useEffect = React.useEffect
      const useRef = React.useRef
      /**
       * @name 看图猜成语
       * @description 1. 点击图片切换成语; 2. 鼠标移入答案双箭头中间位置显示成语
       * @tip react 原始的写法 + axios
       */
      class GuessIdiom extends React.Component {
        constructor(props) {
          super(props)
          this.state = {
            imgUrl: '',
            idiom: '',
          }
        }
        getIdiom = () => {
          axios.get(`${proxyInterface}?url=http://api.botwl.cn/api/ktccy`).then(({ data }) => {
            this.setState({ imgUrl: data.img })
            this.setState({ idiom: data.msg })
          })
        }

        componentDidMount() {
          this.getIdiom()
        }

        render() {
          return ele('section', { className: 'container' }, [
            ele('h2', { key: 'title' }, '看图猜成语'),
            ele('img', {
              key: 'img',
              src: this.state.imgUrl,
              alt: 'img',
              title: '点击换图',
              style: { cursor: 'pointer', width: '70%', objectFit: 'contain' },
              onClick: this.getIdiom,
            }),
            ele('h4', { key: 'idiom-text', className: 'idiom-text', style: { fontSize: '24px' } }, [
              `答案: → `,
              ele(
                'span',
                {
                  key: 'idiom',
                  style: { opacity: 0, cursor: 'pointer' },
                  onMouseEnter: (e) => (e.target.style.opacity = 1),
                  onMouseLeave: (e) => (e.target.style.opacity = 0),
                },
                `${this.state.idiom}`
              ),
              ` ←`,
            ]),
          ])
        }
      }

      /**
       * @name 求签
       * @description 1. 双击卡片标题重新求签
       * @tip class + jsx + axios
       */
      class PraySticks extends React.Component {
        state = {
          // 签诗
          sticksPoem: '',
          // 解签
          sticksResolve: '',
        }
        handlePraySticks = async () => {
          let { data } = await axios.get(`${proxyInterface}?url=http://api.botwl.cn/api/qiuqian`)
          // 签诗
          const sticksPoem = data.split('[\\n]')[0]
          // 解签
          const sticksResolve = data.split('[\\n]')[1]
          this.setState({ sticksPoem, sticksResolve })
        }

        componentDidMount() {
          this.handlePraySticks()
        }

        render() {
          const { sticksPoem, sticksResolve } = this.state
          return (
            <React.Fragment>
              <section className='container pray-sticks'>
                <h2 className='title' title='双击重抽' onDoubleClick={this.handlePraySticks}>
                  求签
                </h2>
                <div className='content'>
                  <p dangerouslySetInnerHTML={{ __html: sticksPoem }} />
                  <p dangerouslySetInnerHTML={{ __html: sticksResolve }} />
                </div>
              </section>
            </React.Fragment>
          )
        }
      }

      /**
       * @name 网易云音乐
       * @description 1. 搜索音乐; 2. 封面点击播放/暂停音乐
       * @tip 函数组件 + hooks + jsx + fetch
       */
      const NeteaseMusic = () => {
        const [songKeyword, setSongKeyword] = useState('Numb - Linkin Park')
        const [songInfo, setSongInfo] = useState({})
        const [playing, setPlaying] = useState(false)
        const audioPlayerDOM = document.querySelector('#audio-player')

        // 搜索歌曲
        const searchSong = () => {
          fetch(`${proxyInterface}?url=http://api.botwl.cn/api/wyy?msg=${songKeyword}&type=json&n=1`).then(
            async (res) => {
              const originData = await res.text()
              const data = JSON.parse(originData.replace('json:', '')).meta.music
              setSongInfo(data)
            }
          )
        }

        // 提交
        const handleSubmit = (e) => {
          e.preventDefault()
          searchSong()
        }

        // 播放/暂停
        const handlePlayAndPause = () => {
          const playingStatus = !playing
          setPlaying(playingStatus)
          playingStatus ? audioPlayerDOM.play() : audioPlayerDOM.pause()
        }

        useEffect(() => {
          document.querySelector('#audio-player').volume = 0.5
          searchSong()
        }, [])

        return (
          <section className='container netease-music'>
            <h2 className='title'>网易云音乐</h2>
            <form onSubmit={handleSubmit}>
              <input
                type='text'
                placeholder='请输入歌名'
                value={songKeyword}
                onChange={(e) => setSongKeyword(e.target.value)}
                style={{ width: '70%', height: 26, borderRadius: 4 }}
              />
              &ensp; <button>搜索</button>
              <div className='content'>
                <p>
                  <img
                    onClick={handlePlayAndPause}
                    src={songInfo.preview}
                    className={`preview ${playing ? 'preview-rotation' : ''}`}
                  />
                </p>
                <p>歌名: {songInfo.title}</p>
                <p>歌手: {songInfo.desc}</p>
                <p>
                  <audio
                    id='audio-player'
                    autoPlay
                    controls
                    onPlay={() => setPlaying(true)}
                    onPause={() => setPlaying(false)}
                    onEnded={() => setPlaying(false)}
                    src={songInfo.musicUrl}
                    style={{ width: '90%', height: 30 }}
                  >
                    您的浏览器不支持 audio 元素。
                  </audio>
                </p>
              </div>
            </form>
          </section>
        )
      }

      /**
       * @name 短视频
       * @description 1. 切换视频
       * @tip 函数组件 + hooks + jsx + fetch
       */
      const ShortVideo = () => {
        const [timestamp, setTimestamp] = useState(Date.now())
        // 是否静音
        const [muted, setMuted] = useState(true)
        // 是否全屏
        const [isFullScreen, setIsFullScreen] = useState(false)
        // 是否自动切换
        const [autoSwitch, setAutoSwitch] = useState(false)
        const videoRef = useRef()

        // 全屏
        const handleFullScreen = () => {
          const documentEle = document.documentElement
          if (documentEle.requestFullscreen) {
            videoRef.current.requestFullscreen()
          } else if (documentEle.mozRequestFullScreen) {
            videoRef.current.mozRequestFullScreen()
          } else if (ele.webkitRequestFullScreen) {
            videoRef.current.webkitRequestFullScreen()
          }
        }

        // 全屏状态改变
        document.addEventListener('fullscreenchange', (e) => {
          setIsFullScreen(!isFullScreen)
        })

        return (
          <section className='container short-video'>
            <h2 className='title'>短视频</h2>
            <div className='content'>
              <div className='left'>
                <span style={{ color: muted ? '#aaa' : '#000' }} title='是否静音' onClick={() => setMuted(!muted)}>
                  ♪
                </span>
                <span onClick={() => setTimestamp(Date.now())} title='换一个'>
                  ↻
                </span>
                <span
                  style={{ color: autoSwitch ? '#000' : '#aaa' }}
                  title='自动切换'
                  onClick={() => setAutoSwitch(!autoSwitch)}
                >
                  ✲
                </span>
                <span style={{ color: isFullScreen ? '#000' : '#aaa' }} title='全屏控制' onClick={handleFullScreen}>
                  ❏
                </span>
              </div>
              <div className='right'>
                <video
                  className={isFullScreen ? '' : 'video'}
                  ref={videoRef}
                  autoPlay
                  loop={!autoSwitch}
                  muted={muted}
                  onClick={(e) => (e.target.paused ? e.target.play() : e.target.pause())}
                  onVolumeChange={(e) => setMuted(e.target.muted)}
                  onEnded={(e) => setTimestamp(Date.now())}
                  onDoubleClick={handleFullScreen}
                  // src='https://www.runoob.com/try/demo_source/mov_bbb.mp4'
                  // src={`https://tucdn.wpon.cn/api-girl/index.php?wpon=302&t=${timestamp}`}
                  src={`https://v.api.aa1.cn/api/api-dy-girl/index.php?aa1=ajdu987hrjfw&t=${timestamp}`}
                ></video>
              </div>
            </div>
          </section>
        )
      }

      /**
       * @name 虎牙主播信息
       * @description 1. 主播信息搜索
       * @tip 函数组件 + hooks + jsx + fetch
       */
      const HuYa = () => {
        const [anchorKeyword, setAnchorKeyword] = useState('呆妹儿')
        const [anchorInfo, setAnchorInfo] = useState({})
        // 搜索主播信息
        const searchAnchorInfo = () => {
          // 空值判断
          if (!anchorKeyword.trim()) return false
          fetch(`${proxyInterface}?url=http://api.botwl.cn/api/huya?msg=${anchorKeyword}&n=1`).then(async (res) => {
            const originData = await res.text()
            // 切割返回的数据
            const splitData = originData.split('\n')
            // 主播信息(临时值)
            const anchorInfoTemp = {}
            // 长度为1，表示查不到主播信息
            if (splitData.length === 1) {
              const key = splitData[0]
              const value = ''
              anchorInfoTemp[key] = value
            }
            // ※ 由于列表搜索接口经常搜不到，所以先注释 ※
            // 第一项不包含 '±img='，则搜索结果为主播列表
            // else if (!splitData[0].includes('±img=')) {
            //   splitData.forEach((item) => {
            //     // unicode 编码转换中文
            //     const chineseItem = eval("'" + item.replace('：', ': ') + "'")
            //     const value = chineseItem.split(': ')[1] && eval("'" + chineseItem.split(': ')[1] + "'")
            //     const key = chineseItem.split(': ')[0] + (value ? '：' : '')
            //     anchorInfoTemp[key] = value
            //   })
            // }
            else {
              const imgUrl = splitData[0].replace('±img=', '')
              anchorInfoTemp.imgUrl = imgUrl
              splitData.splice(1).forEach((item) => {
                const chineseItem = item.split('：')
                const key = chineseItem[0] + '：'
                // unicode 编码转换中文
                const value = chineseItem[1] && eval("'" + chineseItem[1] + "'")
                anchorInfoTemp[key] = value
              })
            }
            setAnchorInfo({ ...anchorInfoTemp })
          })
        }

        useEffect(() => {
          searchAnchorInfo()
        }, [])

        return (
          <section className='container hu-ya'>
            <h2 className='title'>虎牙主播信息</h2>
            <form
              style={{ paddingBottom: 20 }}
              onSubmit={(e) => {
                e.preventDefault()
                searchAnchorInfo()
              }}
            >
              <input
                type='text'
                placeholder='请输入主播信息'
                value={anchorKeyword}
                onChange={(e) => setAnchorKeyword(e.target.value)}
                style={{ width: '70%', height: 26, borderRadius: 4 }}
              />
              &ensp; <button>搜索</button>
            </form>
            {Object.keys(anchorInfo).map((key) =>
              key === 'imgUrl' ? (
                <img
                  key={key}
                  src={anchorInfo[key]}
                  alt='anchor'
                  style={{ width: 80, height: 80, borderRadius: '5%', objectFit: 'fill' }}
                />
              ) : (
                <div key={key}>
                  {key}
                  {anchorInfo[key] && anchorInfo[key].includes('http') ? (
                    <a href={anchorInfo[key]} target='_blank'>
                      {anchorInfo[key]}
                    </a>
                  ) : (
                    anchorInfo[key]
                  )}
                </div>
              )
            )}
          </section>
        )
      }

      const root = ReactDOM.createRoot(document.getElementById('app'))
      root.render([
        ele(GuessIdiom, { key: 'GuessIdiom' }),
        ele(PraySticks, { key: 'PraySticks' }),
        ele(NeteaseMusic, { key: 'NeteaseMusic' }),
        ele(ShortVideo, { key: 'ShortVideo' }),
        ele(HuYa, { key: 'HuYa' }),
      ])
    </script>
  </body>
</html>
